////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2016-2018 Qualcomm Technologies, Inc.
// All Rights Reserved.
// Confidential and Proprietary - Qualcomm Technologies, Inc.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// @file  camxpipeline.h
/// @brief Pipeline class declaration
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#ifndef CAMXPIPELINE_H
#define CAMXPIPELINE_H

#include "camxatomic.h"
#include "camxchicontext.h"
#include "camxcommontypes.h"
#include "camxdeferredrequestqueue.h"
#include "camxdefs.h"
#include "camxhal3types.h"
#include "camximageformatutils.h"
#include "camxsession.h"
#include "camxsettingsmanager.h"
#include "camxthreadmanager.h"
#include "camxtypes.h"

CAMX_NAMESPACE_BEGIN

/// Forward Declarations
enum class ChiFormatType;
enum class DebugDataType;

class  HwContext;
class  HwFactory;
class  ImageBufferManager;
class  MetadataPool;
class  Node;
class  Pipeline;
class  Session;
class  CmdBuffer;
class  CmdBufferManager;

struct NodeProcessRequestData;
struct Usecase;

/// @brief Pipeline create status
enum class PipelineCreateStatus
{
    UNINITIALIZED,              ///< initial status
    INITIALIZED,                ///< Status after pipeline initialize
    FINALIZED,                  ///< Status after pipeline finalization
    MAX_PIPELINE_CREATE_STATUS  ///< Maxium status
};

/// @brief Pipeline flags
struct PipelineFlags
{
    struct
    {
        BIT hasStatsNode            : 1;    ///< Is there a stats node in this pipeline or not
        BIT isSecureMode            : 1;    ///< Is secure mode
        BIT enableQTimer            : 1;    ///< Use Qtimer
        BIT isInitialConfigPending  : 1;    ///< Is initial config pending
        BIT isHFRMode               : 1;    ///< Is HFR Mode
        BIT reserved                : 27;   ///< Reserved fields
    };

    UINT32 allFlagsValue;           ///< Value of all flags combined
};

/// @brief Pipeline finalize create data
struct FinalizeInitializationData
{
    HwContext*               pHwContext;                     ///< Hw context pointer
    DeferredRequestQueue*    pDeferredRequestQueue;          ///< DRQ
    MetadataPool*            pDebugDataPool;                 ///< Debug-data request data pool pointer
    Session*                 pSession;                       ///< Session
    ThreadManager*           pThreadManager;                 ///< Pointer to Thread Manager
    UINT                     usecaseNumBatchedFrames;        ///< Number of batched frames in a usecase
    UINT                     numSessionPipelines;            ///< Number of pipelines in the Session that this pipeline belongs
    BIT                      enableQTimer;                   ///< Qtimer flag
    const ChiSensorModeInfo* pSensorModeInfo;                ///< Sensor mode
    JobHandle                hThreadJobFamilyHandle;         ///< Job handle to be used for job submission
    UINT32                   resourcePolicy;                 ///< Prefered resource vs power trade-off
};

/// @brief Pipeline create input data
struct PipelineCreateInputData
{
    ChiContext*               pChiContext;                  ///< ChiContext pointer
    const PipelineDescriptor* pPipelineDescriptor;          ///< Pipeline descriptor
    UINT                      pipelineIndex;                ///< Pipeline Index from the Session
    BOOL                      isRealTime;                   ///< Is it a real time pipeline

    BOOL                      isSecureMode;                 ///< Mode of pipeline Secure/Non-secure
};

/// @brief Pipeline create output data
struct PipelineCreateOutputData
{
    Pipeline*                pPipeline;                 ///< Created pipeline
    UINT32                   numInputs;                 ///< Number of inputs
    /// @todo (CAMX-1512) Instead of Chi structures use wrappers
    ChiPipelineInputOptions* pPipelineInputOptions;     ///< Input buffer requirements for the create pipeline
};

/// @brief Information about a single frame in a batch
struct PerBatchedFrameInfo
{
    UINT32          sequenceId;                             ///< Framework frame number
    UINT            activeStreamIdMask;                     ///< Active Stream Id Mask
    BufferHandle*   phBuffers[MaxNumStreams];               ///< Native Handles corresponding to activeStreamIds[index];
                                                            ///  Buffers for the active streams indexed with streamId
};

/// @brief Pipeline capture request data.
struct PipelineProcessRequestData
{
    CaptureRequest*     pCaptureRequest;                        ///< Current capture request
    PerBatchedFrameInfo perBatchedFrameInfo[MaxBatchedFrames];  ///< Information about all batched frames
};

/// @brief Information pertaining to per request active streams
struct PerRequestInfo
{
    UINT                        aMetadataReady;                    ///< 1, one of SOF or numNodesMetadataDone == numNodes done
                                                                   ///  0, both remain
    UINT                        numNodesRequestIdDone;             ///< Number of nodes that are done processing
    UINT                        numNodesMetadataDone;              ///< Number of nodes that are done generating metadata
    UINT                        numNodesConfigDone;                ///< Number of nodes that are done config
    UINT32                      sequenceId[MaxBatchedFrames];      ///< Sequence ID mapped to each batch of the request
    BOOL                        isSensorTimestampValid;            ///< Flag for valid sensor time stamp value has been set
    UINT64                      batchFrameIntervalNanoSeconds;     ///< batch frame interval for HFR usecase
    CaptureRequest              request;                           ///< Copy of request from session
    LightweightDoublyLinkedList fences;                            ///< Fences registered for request
};

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// @brief Class that implements the hwl pipeline.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class Pipeline
{
public:
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// Create
    ///
    /// @brief  Static function to create the concrete pipeline object.
    ///
    /// @param  pCreateInputData    pipeline create input data
    /// @param  pCreateOutputData   pipeline create output data
    ///
    /// @return CamxResultSuccess if successful.
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    static CamxResult Create(
        PipelineCreateInputData*  pCreateInputData,
        PipelineCreateOutputData* pCreateOutputData);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// Destroy
    ///
    /// @brief  Destroy the pipeline object.
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    VOID Destroy();

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// GetCSLDevices
    ///
    /// @brief  Get CSL device handles
    ///
    /// @return CSLDeviceHandle*
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CSLDeviceHandle* GetCSLDevices()
    {
        return m_hDevices;
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// GetCSLSyncLink
    ///
    /// @brief  Get CSL link handles
    ///
    /// @return CSLLinkHandle*
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CSLLinkHandle GetCSLSyncLink()
    {
        return m_hCSLSyncLinkHandle;
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// GetCSLLink
    ///
    /// @brief  Get CSL link handles
    ///
    /// @return CSLLinkHandle*
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CSLLinkHandle* GetCSLLink()
    {
        return &m_hCSLLinkHandle;
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// PrepareStreamOn
    ///
    /// @brief  Method that is called by HAL device before streamOn is sent to HW.
    ///
    /// @return CamxResultSuccess if successful
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CamxResult PrepareStreamOn();

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// StreamOn
    ///
    /// @brief  Method to stream on
    ///
    /// @return CamxResultSuccess if successful
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CamxResult StreamOn();

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// StreamOff
    ///
    /// @brief  Method to stream off
    ///
    /// @param  modeBitmask Stream off mode bitmask
    ///
    /// @return CamxResultSuccess if successful
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CamxResult StreamOff(
        CHIDEACTIVATEPIPELINEMODE modeBitmask);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// Link
    ///
    /// @brief  Link pipeline
    ///
    /// @return CamxResultSuccess if successful
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CamxResult Link();

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// Unlink
    ///
    /// @brief  Unlink pipeline
    ///
    /// @return CamxResultSuccess if successful
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CamxResult Unlink();

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// GetDualCameraSyncEnabled
    ///
    /// @brief  Method to get the sync enabled info which is required for syncing both the real time requests
    ///
    /// @param  requestId           Capture request id
    ///
    /// @return TRUE/FALSE
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    BOOL GetDualCameraSyncEnabled(
        UINT64 requestId);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// OpenRequest
    ///
    /// @brief  Method to open CSL process request.
    ///
    /// @param  requestId           Capture request id
    /// @param  CSLSyncID           CSL sync id for the request
    ///
    /// @return CamxResultSuccess   if successful
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CamxResult OpenRequest(
        UINT64 requestId,
        UINT64 CSLSyncID);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// ProcessRequest
    ///
    /// @brief  Method to trigger process request.
    ///
    /// @param  pPipelineRequestData Pipeline process request data
    ///
    /// @return CamxResultSuccess if successful
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CamxResult ProcessRequest(
        PipelineProcessRequestData* pPipelineRequestData);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// NotifyNodeRequestIdDone
    ///
    /// @brief  Nodes call this function when they are done generating all their outputs for a requestId
    ///
    /// @param  requestId RequestId for which the outputs are generated
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CAMX_INLINE VOID NotifyNodeRequestIdDone(
        UINT64 requestId)
    {
        UINT            perRequestIdIndex = requestId % MaxPerRequestInfo;
        PerRequestInfo* pPerRequestInfo   = &m_perRequestInfo[perRequestIdIndex];

        if (m_nodeCount == CamxAtomicIncU(&(pPerRequestInfo->numNodesRequestIdDone)))
        {
            CAMX_LOG_PERF_INFO(CamxLogGroupCore, "All nodes complete with requestId: %llu.", requestId);
        }
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// NotifyNodeMetadataDone
    ///
    /// @brief  Nodes call this function when they are done generating all their metadata for a requestId
    ///
    /// @param  requestId RequestId for which the metadata are generated
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CAMX_INLINE VOID NotifyNodeMetadataDone(
        UINT64 requestId)
    {
        UINT            perRequestIdIndex = requestId % MaxPerRequestInfo;
        PerRequestInfo* pPerRequestInfo   = &m_perRequestInfo[perRequestIdIndex];

        if (m_nodeCount == CamxAtomicIncU(&(pPerRequestInfo->numNodesMetadataDone)))
        {
            CAMX_LOG_PERF_INFO(CamxLogGroupCore, "All nodes complete metadata with requestId: %llu.", requestId);
            BOOL sofOutstanding =
                CamxAtomicCompareExchangeU(&m_perRequestInfo[requestId % MaxPerRequestInfo].aMetadataReady, 0, 1);

            if (FALSE == sofOutstanding)
            {
                if (TRUE == RequestInErrorState(requestId))
                {
                    ProcessMetadataRequestIdError(requestId);
                }
                else
                {
                    ProcessMetadataRequestIdDone(requestId, FALSE);
                }
            }
        }
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// ProcessMetadataRequestIdDone
    ///
    /// @brief  Process when result metadata is ready to send to framework for a perticular request id
    ///
    /// @param  requestId     The request id the metadata applies to.
    /// @param  earlyMetadata TRUE if metadata is the early metadata
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    VOID ProcessMetadataRequestIdDone(
        UINT64 requestId,
        BOOL   earlyMetadata);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// ProcessMetadataRequestIdError
    ///
    /// @brief  Process when result metadata is ready but the request had an error
    ///
    /// @param  requestId     The request id the metadata applies to.
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    VOID ProcessMetadataRequestIdError(
        UINT64 requestId);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// NotifyNodeConfigDone
    ///
    /// @brief  Nodes call this function when they have submitted HW config request
    ///
    /// @param  requestId RequestId for which HW config request is submitted
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CAMX_INLINE VOID NotifyNodeConfigDone(
        UINT64 requestId)
    {
        UINT            perRequestIdIndex   = requestId % MaxPerRequestInfo;
        PerRequestInfo* pPerRequestInfo     = &m_perRequestInfo[perRequestIdIndex];

        if (m_numConfigDoneNodes == CamxAtomicIncU(&(pPerRequestInfo->numNodesConfigDone)))
        {
            // signal the the thread that is waiting for config done
            m_pConfigDoneLock->Lock();

            m_configDoneCount++;
            CAMX_LOG_PERF_INFO(CamxLogGroupCore,
                               "All nodes complete stream config with requestId: %llu., config done count %d",
                               requestId, m_configDoneCount);

            m_pWaitForConfigDone->Signal();
            m_pConfigDoneLock->Unlock();
        }
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// SinkPortFenceSignaled
    ///
    /// @brief  Notification of a fence being triggered/signaled for a sink port
    ///
    /// @param  sinkPortId          Sink port Id
    /// @param  sequenceId          sequenceId of the HALBuffer whose output is available
    /// @param  requestID           RequestId of output available
    /// @param  phHALBuffer         HALBuffer whose output is available
    /// @param  fenceResult         Fence callback is successful or not
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    VOID SinkPortFenceSignaled(
        UINT           sinkPortId,
        UINT32         sequenceId,
        UINT64         requestID,
        BufferHandle*  phHALBuffer,
        CSLFenceResult fenceResult);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// SinkPortFenceErrorSignaled
    ///
    /// @brief  Notification of a fence being triggered/signaled for a sink port
    ///
    /// @param  sinkPortId          Sink port Id
    /// @param  sequenceId          sequenceId of the HALBuffer whose output is available
    /// @param  requestID           RequestId of output available
    /// @param  phHALBuffer         HALBuffer whose output is available
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    VOID  SinkPortFenceErrorSignaled(
        UINT          sinkPortId,
        UINT32        sequenceId,
        UINT64        requestID,
        BufferHandle* phHALBuffer);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// NonSinkPortFenceErrorSignaled
    ///
    /// @brief  Notification of a fence being triggered/signaled for a non sink port in error
    ///
    /// @param  phFence   CSL Fence that got signaled
    /// @param  requestId Request Id for which the fence was signaled
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    VOID NonSinkPortFenceErrorSignaled(
        CSLFence* phFence,
        UINT64    requestId);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// NonSinkPortFenceSignaled
    ///
    /// @brief  Notification of a fence being triggered/signaled for a non sink port
    ///
    /// @param  phFence   CSL Fence that got signaled
    /// @param  requestId Request Id for which the fence was signaled
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    VOID NonSinkPortFenceSignaled(
        CSLFence* phFence,
        UINT64    requestId);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// AddFinalizeBufferPropertiesNodeList
    ///
    /// @brief  Nodes call this function during buffer negotiation to add itself to the list of nodes whose buffer properties
    ///         need to be finalized. This function should be called by the node during the negotiation process STRICTLY only
    ///         when it is ready to generate its input buffer requirement and NEVER before that
    ///
    /// @param  pNode Node to add to the list
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CAMX_INLINE BOOL AddFinalizeBufferPropertiesNodeList(
        Node* pNode)
    {
        // Buffer negotiation is a process in which we walk-back from the sink nodes to the source node and along the way
        // each node informs its parent output port about the buffer dimension/properties it requires the parent to output.
        // This process will terminate at the source node (with no input ports). The source node then determines the final
        // output buffer dimension/properties it is going to generate based on the input buffer requirement it received from
        // its child nodes. For e.g. Sensor will determine the final sensor resolution/mode based on the input buffer
        // requirements from the IFE.
        //
        // Once the source node determines the output buffer dimension/properties we need to walk-forward from the source
        // node to the sink node(s) and along the way each node decides what its final output port buffer dimension/properties
        // will be based on all its input (input meaning what the parent decided for the buffer dimension/properties on its
        // output ports)
        //
        // Walk-forward MUST happen from the source-to-the-sink-nodes and m_ppNodesFinalizeNegotiationOutput is the ordered
        // list of the nodes from the source-to-the-sink-nodes. The ordering is established by the fact that each Node calls
        // this function STRICTLY only after it is ready to generate its input buffer requirement on the walk-back part of the
        // buffer negotiation process

        BOOL    result = TRUE;

        for (UINT32 i = 0 ; i < m_finalizeNegotiationNodeCount; i++)
        {
            if (pNode == m_ppNodesFinalizeNegotiationOutput[i])
            {
                result = FALSE;
                break;
            }
        }
        if (TRUE == result)
        {
            if (m_finalizeNegotiationNodeCount < m_nodeCount)
            {
                m_ppNodesFinalizeNegotiationOutput[m_finalizeNegotiationNodeCount] = pNode;
                m_finalizeNegotiationNodeCount++;
            }
            else
            {
                CAMX_LOG_ERROR(CamxLogGroupCore, "m_finalizeNegotiationNodeCount > m_nodeCount, failure emminent");
            }
        }
        return result;
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// FinalizePipeline
    ///
    /// @brief  Method to finalize the created pipeline
    ///
    /// @param  pFinalizeInitializationData Data required to finalize the initialization
    ///
    /// @return CamxResultSuccess if successful
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CamxResult FinalizePipeline(
        FinalizeInitializationData* pFinalizeInitializationData);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// HasStatsNode
    ///
    /// @brief  Method to query if the pipeline has a stats node in it (so that dependencies per properties can be enforced)
    ///
    /// @return CamxResultSuccess if successful
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    BOOL HasStatsNode() const
    {
        return m_flags.hasStatsNode;
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// IsMasterSensorInput
    ///
    /// @brief  Method to query if the pipeline input is the master sensor input.
    ///
    /// @return CamxResultSuccess if successful
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    BOOL IsMasterSensorInput() const
    {
        return IsSensorInput() && (m_sensorSyncMode == MasterMode);
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// GetSyncMode
    ///
    /// @brief  Method to query pipeline sensor hardware sync mode
    ///
    /// @return SensorSyncMode
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    SensorSyncMode GetSyncMode() const
    {
        return m_sensorSyncMode;
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// SetSyncMode
    ///
    /// @brief  Method to Set pipeline sensor hardware sync mode
    ///
    /// @param  sensorSyncMode Sensor hardware sync mode for this pipeline
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    VOID SetSyncMode(
        SensorSyncMode sensorSyncMode)
    {
        m_sensorSyncMode = sensorSyncMode;
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// IsRealTime
    ///
    /// @brief  Method to query if the pipeline is real time
    ///
    /// @return TRUE/FALSE
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    BOOL IsRealTime() const
    {
        return m_pPipelineDescriptor->flags.isRealTime;
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// IsSensorInput
    ///
    /// @brief  Method to query if the pipelines input is sensor
    ///
    /// @return TRUE/FALSE
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    BOOL IsSensorInput() const
    {
        return m_pPipelineDescriptor->flags.isSensorInput;
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// IsSecureMode
    ///
    /// @brief  Method to query if the pipeline is Secure or Non-secure
    ///
    /// @return TRUE if Secure, FALSE if Non-secure
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CAMX_INLINE BOOL IsSecureMode() const
    {
        return m_flags.isSecureMode;
    }
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// CSLMessageHandler
    ///
    /// @brief  This method is a CSL message handler which receives all the events from CSL
    ///
    /// @param  pUserData Pointer to userdata(class object where message handler is registered) sent to the CSL
    /// @param  pMessage  Pointer to CSL frame message
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    static VOID CSLMessageHandler(
        VOID*       pUserData,
        CSLMessage* pMessage);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// GetTuningDataManager
    ///
    /// @brief  Get the Tuning Manager for this HwContext instance
    ///
    /// @return Pointer to Tuning Manager
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CAMX_INLINE TuningDataManager* GetTuningDataManager() const
    {
        return m_pTuningManager;
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// RequestInErrorState
    ///
    /// @brief  Gets current pipeline create status
    ///
    /// @param  requestId Id of the request to get data of
    ///
    /// @return TRUE if error reported
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CAMX_INLINE BOOL RequestInErrorState(
        UINT64 requestId)
    {
        return m_pDeferredRequestQueue->RequestInErrorState(requestId);
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// GetCameraId
    ///
    /// @brief  Get the camera id associated with this pipeline
    ///
    /// @return Camera id
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CAMX_INLINE INT32 GetCameraId() const
    {
        return m_cameraId;
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// GetOutputStreamWrapper
    ///
    /// @brief  Get the pipeline descriptor
    ///
    /// @param  nodeId      Node Id
    /// @param  instanceId  Instance Id
    /// @param  portId      Port Id
    ///
    /// @return Wrapper*
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CAMX_INLINE ChiStreamWrapper* GetOutputStreamWrapper(
        UINT32 nodeId,
        UINT32 instanceId,
        UINT32 portId
        ) const
    {
        ChiStreamWrapper* pChiStreamWrapper = NULL;

        for (UINT i = 0; i < m_pPipelineDescriptor->numOutputs; i++)
        {
            const PipelineOutputData* pPipelineOutputData = &m_pPipelineDescriptor->outputData[i];

            if ((pPipelineOutputData->nodePort.nodeId         == nodeId)     &&
                (pPipelineOutputData->nodePort.nodeInstanceId == instanceId) &&
                (pPipelineOutputData->nodePort.nodePortId     == portId))
            {
                pChiStreamWrapper = pPipelineOutputData->pOutputStreamWrapper;
                break;
            }
        }

        return pChiStreamWrapper;
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// GetInputStreamWrapper
    ///
    /// @brief  Get the pipeline descriptor
    ///
    /// @param  nodeId      Node Id
    /// @param  instanceId  Instance Id
    /// @param  portId      Port Id
    ///
    /// @return Camera id
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CAMX_INLINE ChiStreamWrapper* GetInputStreamWrapper(
        UINT32 nodeId,
        UINT32 instanceId,
        UINT32 portId
        ) const
    {
        ChiStreamWrapper* pChiStreamWrapper = NULL;

        for (UINT i = 0; i < m_pPipelineDescriptor->numInputs; i++)
        {
            const PipelineInputData* pPipelineInputData = &m_pPipelineDescriptor->inputData[i];

            if ((pPipelineInputData->nodePort.nodeId         == nodeId)     &&
                (pPipelineInputData->nodePort.nodeInstanceId == instanceId) &&
                (pPipelineInputData->nodePort.nodePortId     == portId))
            {
                pChiStreamWrapper = pPipelineInputData->pInputStreamWrapper;
                break;
            }
        }

        return pChiStreamWrapper;
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// GetIntraPipelinePerFramePool
    ///
    /// @brief  Get Frame Property/ metadata pool by pipeline ID
    ///
    /// @param  poolType    Type of the per-frame pool asked for
    /// @param  pipelineId  Pipeline ID of the property/ metadata pool want to get
    ///
    /// @return Pointer to the per frame property/metadata pool
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    MetadataPool* GetIntraPipelinePerFramePool(
        PoolType poolType,
        UINT     pipelineId);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// GetIntraRealtimePipelineId
    ///
    /// @brief  Get intra realtime pipeline id
    ///
    /// @param  inputPipelineId   The pipeline id of pipeline which need get its intra pipeline
    /// @param  pIntraPipelineId  The result intra pipeline found
    ///
    /// @return CamxResultSuccess if successful
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CamxResult GetIntraRealtimePipelineId(
        UINT     inputPipelineId,
        UINT*    pIntraPipelineId);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// IsDualCamera
    ///
    /// @brief  Is Dual Camera use case or not.
    ///         This needs to be called once session::Initialize has trigerred otherwise it always return false.
    ///         Need to remove this logic after CHI create pipeline has capability to send extra vendor specifc information.
    ///
    /// @return True if corresponding session has two real time pipelines, False if not
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CAMX_INLINE BOOL IsDualCamera()
    {
        BOOL dualCamera = FALSE;

        if (NULL != m_pSession)
        {
            dualCamera = m_pSession->IsDualCamera();
        }

        return dualCamera;
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// GetPipelineId
    ///
    /// @brief  Get current pipeline id
    ///
    /// @return pipeline id
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CAMX_INLINE UINT GetPipelineId()
    {
        return m_pipelineIndex;
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// StreamedOn
    ///
    /// @brief  Sets the state of streamed on
    ///
    /// @param  state state
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CAMX_INLINE VOID StreamedOn(
        BOOL state)
    {
        m_isStreamedOn = state;
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// IsStreamedOn
    ///
    /// @brief  Is streamed on
    ///
    /// @return VOID
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CAMX_INLINE BOOL IsStreamedOn()
    {
        return m_isStreamedOn;
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// InitializeMetadataPools
    ///
    /// @brief  Call to initialize metadata pools of a pipeline
    ///
    /// @param  numSlots Number of slots each pool should allocate
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    VOID InitializeMetadataPools(
        UINT numSlots);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// GetPerFramePool
    ///
    /// @brief  Gets the pointer to the per frame property/metadata pool
    ///
    /// @param  poolType Type of the per-frame pool asked for
    ///
    /// @return Pointer to the per frame property/metadata pool
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CAMX_INLINE MetadataPool* GetPerFramePool(
        PoolType poolType)
    {
        MetadataPool* pPool = NULL;

        switch (poolType)
        {
            case PoolType::PerFrameInput:
                pPool = m_pInputPool;
                break;
            case PoolType::PerFrameResult:
                pPool = m_pMainPool;
                break;
            case PoolType::PerFrameResultEarly:
                pPool = m_pEarlyMainPool;
                break;
            case PoolType::PerFrameInternal:
                pPool = m_pInternalPool;
                break;
            case PoolType::PerUsecase:
                pPool = m_pUsecasePool;
                break;
            case PoolType::PerFrameEmptyMetadata:
                pPool = m_pEmptyMetaDataPool;
                break;
            default:
                CAMX_LOG_ERROR(CamxLogGroupCore, "Invalid pool type %d", poolType);
                break;
        }

        return pPool;
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// GetNumBatchedFrames
    ///
    /// @brief  Gets number of batched frames of this pipeline from usecase pool
    ///
    /// @return Number of batched frames
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    UINT GetNumBatchedFrames();

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// GetFPSValue
    ///
    /// @brief  Gets fps value of this pipeline from usecase pool
    ///
    /// @return Fps value
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    UINT GetFPSValue();

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// GetRequest
    ///
    /// @brief  Gets the pointer to the request structure for the provided requestId
    ///
    /// @param  requestId Id of the request to get data of
    ///
    /// @return Pointer to the CaptureRequest
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CAMX_INLINE CaptureRequest* GetRequest(
        UINT64 requestId)
    {
        return &m_perRequestInfo[requestId % MaxPerRequestInfo].request;
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// RegisterRequestFence
    ///
    /// @brief  Record a fence for a request
    ///
    /// @param  phFence   Fence for the request
    /// @param  requestId Id of the request
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CAMX_INLINE VOID RegisterRequestFence(
        CSLFence* phFence,
        UINT64    requestId)
    {
        m_pPerRequestInfoLock->Lock();
        LightweightDoublyLinkedListNode* pNode =
            reinterpret_cast<LightweightDoublyLinkedListNode*>(CAMX_CALLOC(sizeof(LightweightDoublyLinkedListNode)));

        if (NULL != pNode)
        {
            pNode->pData = phFence;
            m_perRequestInfo[requestId % MaxPerRequestInfo].fences.InsertToTail(pNode);
        }
        else
        {
            CAMX_LOG_ERROR(CamxLogGroupCore, "Out of memory to allocate node");
        }
        m_pPerRequestInfoLock->Unlock();
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// RemoveRequestFence
    ///
    /// @brief  Record a fence for a request
    ///
    /// @param  phFence   Fence for the request
    /// @param  requestId Id of the request
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CAMX_INLINE VOID RemoveRequestFence(
        CSLFence* phFence,
        UINT64    requestId)
    {
        m_pPerRequestInfoLock->Lock();
        LightweightDoublyLinkedListNode* pNode = m_perRequestInfo[requestId % MaxPerRequestInfo].fences.Head();
        LightweightDoublyLinkedListNode* pNext = NULL;

        while (NULL != pNode)
        {
            pNext = LightweightDoublyLinkedList::NextNode(pNode);

            if (phFence == pNode->pData)
            {
                m_perRequestInfo[requestId % MaxPerRequestInfo].fences.RemoveNode(pNode);
                CAMX_FREE(pNode);
            }
            pNode = pNext;
        }
        m_pPerRequestInfoLock->Unlock();
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// GetPipelineCreateStatus
    ///
    /// @brief  Get current pipeline create status
    ///
    /// @return current pipeline create status
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CAMX_INLINE PipelineCreateStatus GetPipelineCreateStatus()
    {
        return m_currentCreateStatus;
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// DumpState
    ///
    /// @brief  Dumps snapshot of current state to a file
    ///
    /// @param  fd      file descriptor
    /// @param  indent  indent spaces.
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    VOID DumpState(
        INT     fd,
        UINT32  indent);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// IsNodeExist
    ///
    /// @brief  Check if corresponding node exist in the pipeline
    ///
    /// @param  nodeType   node type
    ///
    /// @return TRUE if find the node, otherwise FALSE
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    BOOL IsNodeExist(
        UINT nodeType);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// HasSnapshotJPEGStream
    ///
    /// @brief  Check if the pipeline has snapshot JPEG stream
    ///
    /// @return TRUE if the pipeline has snapshot JPEG stream, otherwise FALSE
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    BOOL HasSnapshotJPEGStream();

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// DetermineFrameDelay
    ///
    /// @brief  Determine the frame delay of the pipeline
    ///
    /// @return Return the value of the pipeline's frame delay
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    UINT32 DetermineFrameDelay();

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// GetRequestQueueDepth
    ///
    /// @brief  Determine the request queue depth of the pipeline. Function must be called after the Pipeline creates and
    ///         initializes it's nodes
    ///
    /// @return Return the value of the pipeline's request queue depth
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    UINT32 GetRequestQueueDepth();

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// Flush
    ///
    /// @brief  Flush on pipeline
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    VOID Flush();

protected:
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// Pipeline
    ///
    /// @brief  Constructor
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    Pipeline();

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// ~Pipeline
    ///
    /// @brief  Destructor
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    virtual ~Pipeline();

private:
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// Initialize
    ///
    /// @brief  Method to initialize Pipeline object.
    ///
    /// @param  pCreateInputData    Pipeline create input data
    /// @param  pCreateOutputData   Pipeline create output data
    ///
    /// @return CamxResultSuccess if successful
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CamxResult Initialize(
        PipelineCreateInputData*  pCreateInputData,
        PipelineCreateOutputData* pCreateOutputData);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// CreateNodes
    ///
    /// @brief  Method to create Node object instances for the current pipeline usecase selection.
    ///
    /// @param  pCreateInputData    Pipeline create input data
    /// @param  pCreateOutputData   Pipeline create output data
    ///
    /// @return CamxResultSuccess if successful
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CamxResult CreateNodes(
        PipelineCreateInputData*  pCreateInputData,
        PipelineCreateOutputData* pCreateOutputData);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// DestroyNodes
    ///
    /// @brief  Method to destroy Node object instances previously created for matching pipeline usecase selection.
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    VOID DestroyNodes();

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// GetNode
    ///
    /// @brief  Get node pointer for a given type and instance id
    ///
    /// @param  nodeType   node type
    /// @param  instanceId instance id of the node
    ///
    /// @return Corresponding node pointer
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    Node* GetNode(
        UINT nodeType,
        UINT instanceId);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// SendOfflineShutterNotification
    ///
    /// @brief  Send shutter event for offline processing
    ///
    /// @param  requestId  id of the request to send
    /// @param  pTimestamp pointer to the timestamp
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    VOID SendOfflineShutterNotification(
        UINT64 requestId,
        UINT64* pTimestamp);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// SendShutterNotification
    ///
    /// @brief  Send shutter notification based on CSL frame message
    ///
    /// @param  pMessage CSL frame message
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    VOID SendShutterNotification(
        const CSLFrameMessage* pMessage);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// SendErrorNotification
    ///
    /// @brief  Send error notification based on CSL error message
    ///
    /// @param  pMessage CSL error message
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    VOID SendErrorNotification(
        const CSLErrorMessage* pMessage);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// SendSOFNotification
    ///
    /// @brief  Send SOF notification based on CSL frame message
    ///
    /// @param  pMessage CSL frame message
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    VOID SendSOFNotification(
        const CSLFrameMessage* pMessage);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// RenegotiateInputBufferRequirement
    ///
    /// @brief  Method to switch node output format to NV12 and renegotiate
    ///
    /// @param  pCreateInputData    Pipeline create input data
    /// @param  pCreateOutputData   Pipeline create output data
    ///
    /// @return CamxResultSuccess if successful
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CamxResult RenegotiateInputBufferRequirement(
        PipelineCreateInputData*  pCreateInputData,
        PipelineCreateOutputData* pCreateOutputData);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// FinalizeSensorModeInitalization
    ///
    /// @brief  Sensor mode intialization for External Sensors
    ///
    /// @param  pSensorModuleData    Image sensor module data
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    VOID FinalizeSensorModeInitalization(
        const ImageSensorModuleData*  pSensorModuleData);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// SetNumBatchedFrames
    ///
    /// @brief  SetNumBatchedFrames.
    ///
    /// @param  usecaseNumBatchedFrames        Number of batched frames
    /// @param  usecaseFPSValue                FPS info of batched frames
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    VOID SetNumBatchedFrames(
        UINT usecaseNumBatchedFrames,
        UINT usecaseFPSValue);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// InitializeDebugDataBuffer
    ///
    /// @brief  Initialize debug/tuning data buffer, setting data blocks as un-used.
    ///
    /// @param  requestId   Request ID
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    VOID InitializeDebugDataBuffer(
        UINT64 requestId);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// SealDebugDataBuffer
    ///
    /// @brief  Initialize debug/tuning data buffer, setting data blocks as un-used.
    ///
    /// @param  dataType    Debug-data type block to be seal/init
    /// @param  pDebugData  Curresponding debug-data buffer for the slot
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    VOID SealDebugDataBuffer(
        DebugDataType   dataType,
        DebugData*      pDebugData);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// PublishOutputDimensions
    ///
    /// @brief  Publish pipeline output dimensions
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    VOID PublishOutputDimensions();

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// PublishTargetFPS
    ///
    /// @brief  Publish pipeline target FPS
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    VOID PublishTargetFPS();

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// PublishSensorModeInformation
    ///
    /// @brief  Publish sensor mode information
    ///
    /// @param  requestId This is the request ID to publish the metadata
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    VOID PublishSensorModeInformation(
        UINT64 requestId);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// PublishSensorUsecaseProperties
    ///
    /// @brief  Publish sensor related information to usecase pool in case of offline pipeline
    ///
    /// @param  pSensorModuleData    Image sensor module data
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    VOID PublishSensorUsecaseProperties(
        const ImageSensorModuleData* pSensorModuleData);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// ConvertQTimerTimestampToMonotonicSystemTimestamp
    ///
    /// @brief  This function converts the QTimer timestamp which was reported by KMD to the MONOTONIC system timestamp
    ///
    /// @param  requestId  request ID
    /// @param  qTimestamp QTimer timestamp
    ///
    /// @return MONOTONIC timestamp
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    UINT64 ConvertQTimerTimestampToMonotonicSystemTimestamp(
        UINT64 requestId,
        UINT64 qTimestamp);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// QueryEISCaps
    ///
    /// @brief  Fill EIS caps
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    VOID QueryEISCaps()
    {
        const StaticSettings* pSettings = HwEnvironment::GetInstance()->GetStaticSettings();

        if (TRUE == pSettings->EISV2Enable)
        {
            /// @todo (CAMX-3135) Need to check node capabilities once that code is available
            m_videoStabilizationCaps = 1;
        }
    }

    Pipeline(const Pipeline&) = delete;                                     ///< Disallow the copy constructor
    Pipeline& operator=(const Pipeline&) = delete;                          ///< Disallow assignment operator

    /// @brief Nodes that contain sink ports
    struct NodesWithSinkPorts
    {
        UINT numNodes;                                                      ///< Number of nodes with sink port(s)
        UINT nodeIndices[MaxNodeType];                                      ///< Index into m_ppNodes that are nodes with
                                                                            ///  sink port(s)
    };

    // Pipeline can never get called to process request 'n + RequestQueueDepth' until Request 'n' is done. But we consider
    // request 'n' to be done if all the outputs (buffers, metadata etc) for request 'n' is available. However there may be
    // nodes, like the StatsNode, that may still not be done for request 'n' and will complete at a later time. After it is
    // done, it will inform Pipeline that it is done for request n.
    //
    // Since request n is done, Pipeline may get called to process request n+RequestQueueDepth, at which time it will reset
    // its internal structures for request n+RequestQueueDepth. If we maintain an array of only RequestQueueDepth, then
    // request n and request n+RequestQueueDepth will map onto the same array element. And when Pipeline starts processing
    // request n+RequestQueueDepth it will reset the array element that was used for request n.
    //
    // Later when, for e.g. StatsNode is done and informs Pipeline for request n, Pipeline will refer to the structure that
    // was reset for request n+RequestQueueDepth!. To avoid the problem, we maintain twice the number of structures to be
    // on the safe side
    static const UINT     MaxPerRequestInfo = RequestQueueDepth * 2;    ///< Max number of per request info structures

    ChiContext*           m_pChiContext;                                ///< Chi context
    HwContext*            m_pHwContext;                                 ///< HW context pointer
    Session*              m_pSession;                                   ///< Session associated with this pipeline
    CSLHandle             m_hCSLSession;                                ///< CSL Session handle
    MetadataPool*         m_pInputPool;                                 ///< Pointer to input metadata pool
    MetadataPool*         m_pMainPool;                                  ///< Pointer to main metadata/property pool
    MetadataPool*         m_pEarlyMainPool;                             ///< Pointer to main metadata/property pool
    MetadataPool*         m_pInternalPool;                              ///< Pointer to internal property pool
    MetadataPool*         m_pUsecasePool;                               ///< Pointer to usecase pool
    MetadataPool*         m_pDebugDataPool;                             ///< Pointer to debug-data pool
    MetadataPool*         m_pEmptyMetaDataPool;                         ///< Pointer to empty metadata pool
    ThreadManager*        m_pThreadManager;                             ///< Pointer to Thread Manager
    Node**                m_ppNodes;                                    ///< Created node pointers
    Node**                m_ppNodesFinalizeNegotiationOutput;           ///< List of nodes to call to finalize their buffer
                                                                        ///  properties
    UINT                  m_finalizeNegotiationNodeCount;               ///< Number of nodes required to finalize the
                                                                        ///  negotiation process
    DeferredRequestQueue* m_pDeferredRequestQueue;                      ///< Pointer to the deferred process handler
    PerRequestInfo        m_perRequestInfo[MaxPerRequestInfo];          ///< Per request info
    Mutex*                m_pPerRequestInfoLock;                        ///< Lock to access m_perRequestInfo
    NodesWithSinkPorts    m_nodesSinkOutPorts;                          ///< Information about nodes with sink port(s)
    NodesWithSinkPorts    m_nodesSourceInPorts;                         ///< Information about nodes with sink port(s)
    UINT                  m_nodeCount;                                  ///< Created node counts for m_ppNodes
    UINT                  m_lastRequestActiveStreamIdMask;              ///< Streams that were active in the last request
    UINT                  m_pipelineIndex;                              ///< Pipeline index in the session
    UINT                  m_numSessionPipelines;                        ///< Number of pipelines in the session this
                                                                        ///  pipeline belongs to
    /// @todo (CAMX-1797) Add back CSLMessage handler
    // CSLMessage            m_CSLMessage;                              ///< CSL frame message
    TuningDataManager*    m_pTuningManager;                             ///< Tuning manager
    PipelineFlags         m_flags;                                      ///< Pipeline flags
    INT32                 m_cameraId;                                   ///< CameraId associated with this pipeline if any
    const PipelineDescriptor* m_pPipelineDescriptor;                    ///< Pipeline descriptor
    UINT32                m_vendorTagIndexAVTimer;                      ///< Index for AV Timer vendor tag
    UINT32                m_vendorTagIndexTimestamp;                    ///< Index for timestamp vendor tag
    CSLLinkHandle         m_hCSLLinkHandle;                             ///< CSL link handle
    CSLLinkHandle         m_hCSLSyncLinkHandle;                         ///< CSL sync link handle
    CSLDeviceHandle       m_hDevices[CamxMaxDeviceIndex];               ///< CSLDeviceHandles
    UINT32                m_currentSensorMode;                          ///< Sensor mode configured during node finalization
    SensorSyncMode        m_sensorSyncMode;                             ///< Sensor hardware sync mode
    BOOL                  m_isStreamedOn;                               ///< Streamed on state
    UINT                  m_numConfigDoneNodes;                         ///< Num nodes the will report config done
    volatile UINT32       m_configDoneCount;                            ///< Config done count per reques, Only freely
                                                                        ///< accessed when holding m_pConfigDoneLock
    Mutex*                m_pConfigDoneLock;                            ///< Config done lock
    Condition*            m_pWaitForConfigDone;                         ///< Wait for config done
    UINT64                m_lastRequestId;                              ///< Last request id before stream off
    BOOL                  m_partialStreamon;                            ///< partial StreamOn
    UINT64                m_lastQTimerTimestamp;                        ///< Last QTimer timestamp
    UINT64                m_lastMonoTimestamp;                          ///< Last MONOTONIC timestamp
    UINT32                m_videoStabilizationCaps;                     ///< EIS capabilities
    UINT64                m_CSLSyncIDToRequestId[MaxPerRequestInfo *
                                                 MaxBatchedFrames];     ///< Mapping from CSL Sync ID to request ID
    volatile PipelineCreateStatus  m_currentCreateStatus;               ///< Flag to indicate pipeline create status
};

CAMX_NAMESPACE_END

#endif // CAMXPIPELINE_H
